﻿using SignalBox.Core.Util;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace SignalBox.Core.Model
{
    public class TrackCell : ICloneable
    {
        private static Dictionary<TRACKCELLTYPE, Bitmap> cellImages;
        private static Dictionary<String, Bitmap> overlayImages;

        static TrackCell()
        {
            cellImages = new Dictionary<TRACKCELLTYPE, Bitmap>();
            overlayImages = new Dictionary<String, Bitmap>();
        }
        private TRACKCELLTYPE type;

        /// <summary>
        /// Locked = false means the signal is red
        /// Locked = true means the signal is green/yellow/double yellow
        /// </summary>
        public bool Locked
        {
            get;
            set;
        }

        public int State
        {
            get;
            set;
        }

        public string Platform
        {
            get;
            set;
        }

        public bool EditMode
        {
            get;
            set;
        }

        public int MaxSpeedLeft
        {
            get;
            set;
        }

        public int MaxSpeedRight
        {
            get;
            set;
        }

        public int RouteFindingState
        {
            get;
            set;
        }


        public TrackCell(bool editMode)
        {
            X = 0;
            Y = 0;
            Type = TRACKCELLTYPE.STR_E_W;
            Length = 1;
            TrackCellType = TrackCellType.TrackCellTypes[type];
            Name = string.Empty;
            Platform = string.Empty;
            Locked = false;
            State = 1;
            EditMode = editMode;
            Occupied = false;
            OccupiedBy = null;
        }

        public Point Location
        {
            get
            {
                return new Point(X, Y);
            }
        }

        public bool Occupied
        {
            get;
            set;
        }


        public int Length
        {
            get;
            set;
        }

        public int X
        {
            get;
            set;
        }
        public int Y
        {
            get;
            set;
        }

        public Train OccupiedBy
        {
            get;
            set;
        }

        public TRACKCELLTYPE Type
        {
            get
            {
                return type;
            }
            set
            {
                type = value;
                TrackCellType = TrackCellType.TrackCellTypes[type];
                if (TrackCellType.Category == "SIGNAL")
                {
                    SignalAspect = SIGNALASPECTTYPE.FOUR;
                }
            }
        }


        private Bitmap getImage()
        {
            if (cellImages.ContainsKey(type))
            {
                return cellImages[type];
            }
            else
            {
                Bitmap image = EditMode ? TrackCellType.GetToolboxImage() : TrackCellType.GetBaseImage();
                if (image != null)
                {

                    image = BitmapUtils.MakeTransparent(image, Color.White);

                    //image.MakeTransparent();

                    cellImages[type] = image;
                    return image;
                }
            }
            return null;
        }

        private Bitmap getOverlayImage(String imageCode, int State)
        {
            if (overlayImages.ContainsKey(imageCode))
            {
                return overlayImages[imageCode];
            }
            else
            {
                var image = TrackCellType.GetOverlayImage(State);
                if (image != null)
                {
                    image.MakeTransparent();

                    overlayImages[imageCode] = image;
                    return image;
                }
            }
            return null;
        }

        public void drawCell(Graphics g)
        {
            var image = getImage();
            var baseX = X * TrackLayout.PIXELSPERCELL;
            var baseY = Y * TrackLayout.PIXELSPERCELL;

            if (Name == "A2")
                Console.WriteLine("Here");

            if (image != null)
            {
                g.TranslateTransform(baseX, baseY);
                g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                g.TranslateTransform(-baseX, -baseY);

                if (TrackCellType.Category == "TRACK")
                {
                    if (!String.IsNullOrEmpty(Name))
                    {
                        g.TranslateTransform(baseX, baseY);
                        g.FillEllipse(new SolidBrush(Color.Blue), TrackLayout.PIXELSPERCELL / 2, TrackLayout.PIXELSPERCELL / 2, 4, 4);
                        g.TranslateTransform(-baseX, -baseY);
                    }
                }

                if (TrackCellType.Category == "ENTRYEXIT" && !String.IsNullOrEmpty(Name))
                {
                    var f = new Font("Verdana", 10);
                    var size = g.MeasureString(Name, f);

                    var width = size.Width;
                    var height = size.Height;

                    float fontX = baseX;
                    float fontY = baseY;

                    if (type == TRACKCELLTYPE.ENTRY_E)
                    {
                        fontX = baseX + TrackLayout.PIXELSPERCELL + 5;
                        fontY = baseY + TrackLayout.PIXELSPERCELL / 2 + height / 2 - 3;
                    }
                    else
                    {
                        if (type == TRACKCELLTYPE.ENTRY_W)
                        {
                            fontX = baseX - 5 - width;
                            fontY = baseY + TrackLayout.PIXELSPERCELL / 2 + height / 2 - 3;
                        }
                        else
                        {
                            if (type == TRACKCELLTYPE.ENTRY_N)
                            {
                                fontX = baseX + TrackLayout.PIXELSPERCELL / 2 - width / 2;
                                fontY = baseY - 5;
                            }
                            else
                            {
                                if (type == TRACKCELLTYPE.ENTRY_S)
                                {
                                    fontX = baseX + TrackLayout.PIXELSPERCELL / 2 - width / 2;
                                    fontY = baseY + TrackLayout.PIXELSPERCELL + height;
                                }
                            }
                        }
                    }
                    g.DrawString(Name, f, new SolidBrush(Color.Blue), fontX, fontY);
                }
            }

            if (EditMode)
            {
                if (Selected)
                {
                    g.TranslateTransform(baseX, baseY);
                    g.DrawRectangle(new Pen(new SolidBrush(Color.Blue)), 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                    g.TranslateTransform(-baseX, -baseY);
                }

                if (LinkedCell != null)
                {
                    g.DrawLine(new Pen(new SolidBrush(Color.Red)), baseX + TrackLayout.PIXELSPERCELL / 2, baseY + TrackLayout.PIXELSPERCELL / 2, LinkedCell.X * TrackLayout.PIXELSPERCELL + TrackLayout.PIXELSPERCELL / 2, LinkedCell.Y * TrackLayout.PIXELSPERCELL + TrackLayout.PIXELSPERCELL / 2);
                }
            }
            else
            {
                if (TrackCellType.BaseBitmap != null && TrackCellType.BaseBitmap != string.Empty)
                {
                    if (!Occupied && Locked && (TrackCellType.Category == "TRACK" || TrackCellType.Category == "ENTRYEXIT"))
                    {
                        image = BitmapUtils.SwapColor(image, Color.Black, Color.Lime);
                    }
                    else if (Occupied && (TrackCellType.Category == "TRACK" || TrackCellType.Category == "ENTRYEXIT"))
                    {
                        image = BitmapUtils.SwapColor(image, Color.Black, Color.Red);
                    }
                    g.TranslateTransform(baseX, baseY);
                    g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                    g.TranslateTransform(-baseX, -baseY);
                }
                if (TrackCellType.Category == "SWITCH")
                {
                    image = getOverlayImage(TrackCellType.ToolbarName + "_" + State, State);

                    if (Locked)
                    {
                        image = BitmapUtils.SwapColor(image, Color.Black, Color.Lime);
                    }
                    g.TranslateTransform(baseX, baseY);
                    g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                    g.TranslateTransform(-baseX, -baseY);
                }
                else
                {
                    if (TrackCellType.Category == "SIGNAL")
                    {

                        int state = State;

                        if (Occupied)
                            state = 1;

                        image = getOverlayImage(TrackCellType.ToolbarName + "_" + state, state);

                        g.TranslateTransform(baseX, baseY);
                        g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                        g.TranslateTransform(-baseX, -baseY);

                        if (Locked && !Occupied)
                        {
                            image = BitmapUtils.SwapColor(getOverlayImage(TrackCellType.ToolbarName + "_" + 0, 0), Color.Black, Color.Lime);

                            g.TranslateTransform(baseX, baseY);
                            g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                            g.TranslateTransform(-baseX, -baseY);
                        }
                        else if (Locked || Occupied)
                        {
                            image = BitmapUtils.SwapColor(getOverlayImage(TrackCellType.ToolbarName + "_" + 0, 0), Color.Black, Color.Red);

                            g.TranslateTransform(baseX, baseY);
                            g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                            g.TranslateTransform(-baseX, -baseY);
                        }
                    }
                    else
                    {
                        if (TrackCellType.Category == "CROSS")
                        {
                            if (Locked)
                            {
                                image = BitmapUtils.SwapColor(getOverlayImage(TrackCellType.ToolbarName + "_" + State, State), Color.Black, Color.Lime);

                                g.TranslateTransform(baseX, baseY);
                                g.DrawImage(image, 0, 0, TrackLayout.PIXELSPERCELL, TrackLayout.PIXELSPERCELL);
                                g.TranslateTransform(-baseX, -baseY);
                            }
                        }
                    }
                }
            }
        }

        public TrackCellType TrackCellType
        {
            get;
            set;
        }

        public bool HasDirection(DIRECTION dir)
        {
            switch (dir)
            {
                case DIRECTION.E:
                    return TrackCellType.HasE;
                case DIRECTION.N:
                    return TrackCellType.HasN;
                case DIRECTION.W:
                    return TrackCellType.HasW;
                case DIRECTION.S:
                    return TrackCellType.HasS;
                case DIRECTION.NE:
                    return TrackCellType.HasNE;
                case DIRECTION.NW:
                    return TrackCellType.HasNW;
                case DIRECTION.SE:
                    return TrackCellType.HasSE;
                case DIRECTION.SW:
                    return TrackCellType.HasSW;
            }

            return false;
        }

        public bool Selected
        {
            get;
            set;
        }

        public TrackCell LinkedCell
        {
            get;
            set;
        }

        public SIGNALASPECTTYPE SignalAspect
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }

        public void performClick()
        {
        }

        public object Clone()
        {
            var tc = new TrackCell(EditMode);
            tc.Selected = false;
            tc.Length = Length;
            tc.LinkedCell = null;
            tc.MaxSpeedLeft = MaxSpeedLeft;
            tc.MaxSpeedRight = MaxSpeedRight;
            tc.Type = Type;
            tc.X = X;
            tc.Y = Y;
            tc.Name = Name;
            tc.Platform = Platform;
            return tc;
        }

        public int GetMaxSpeed(DIRECTION dir)
        {
            int maxSpeed = 0;
            switch (dir)
            {
                case DIRECTION.E:
                case DIRECTION.NE:
                case DIRECTION.SE:
                case DIRECTION.S:
                    maxSpeed = MaxSpeedRight;
                    break;
                default:
                    maxSpeed = MaxSpeedLeft;
                    break;
            }
            return maxSpeed;
        }
    }
}
